#include "N1Debug.h"
#include "N1Lib.h"
#include <stdlib.h>
#include <windows.h>
#include <DbgHelp.h>

void N1Check(bool condition)
{
  if (!(condition))
     N1ThrowException("N1Check failed");
}

void N1Exit()
{
    exit(0);
}

void N1Break()
{
}

void N1Crash()
{
}

#if defined(__SVR4) || defined(__LINUX__)
int N1GetModuleFileNameByAddr( const void *addr, char *buf, size_t bufSize )
#else
int N1GetModuleFileNameByAddr( const void *addr, wchar_t *buf, int bufSize )
#endif
{
#if defined(__WIN32__)
    /* Windows XP has a documented way to get module handle by address
     * (special flag for GetModuleFileNameEx function) but it is not 
     * supported by Win2000. But we know one trick: module handle is 
     * just it's starting address, so we can get module handle and 
     * thus can get module name.
     */
    MEMORY_BASIC_INFORMATION mbi;

    if (VirtualQuery(addr, &mbi, sizeof(mbi)) == 0)
        return 0;

    return GetModuleFileNameW( (HMODULE) mbi.AllocationBase, buf, bufSize );
#elif defined(__SVR4) || defined(__LINUX__)
    Dl_info dlip;
    size_t len;

    if (dladdr((void *)addr, &dlip) == 0)
        return 0;

    len = strlen(dlip.dli_fname);

    if (len > bufSize - 1)                
    {                                     
        len = bufSize - 1;                
        strncpy(buf, dlip.dli_fname, len);
        buf[bufSize-1] = '\0';            
    } else                                
        strcpy(buf, dlip.dli_fname);      

    return len;
#else
#error Not implemented
    return 0;
#endif
}


#ifdef WINDOWS

int N1GetFunctionNameByAddr(N0IntWithPointerSize address, 
                            char* func_name, uint32 size, 
                            N0IntWithPointerSize *offs)
{
    ULONG64 buffer[(sizeof(SYMBOL_INFO) + 255*sizeof(TCHAR) +
                   sizeof(ULONG64) - 1) / sizeof(ULONG64)];
    PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;

    pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
    pSymbol->MaxNameLen = 255;

    if (SymFromAddr(GetCurrentProcess(), address, 0, pSymbol))
    {
        strncpy(func_name, pSymbol->Name, size);
        *offs = address - pSymbol->Address;
        return 1;
    }
    return 0;
}

#endif
